#include "stdafx.h"
#include "ISCServer.h"
#include "ISCPacketCreator.h"

CISCServer::CISCServer(CISCSettings* settings)
	: m_settings(settings), m_acceptor(null)
{
}

int CISCServer::ServerList::getServerCount() const
{
	return Channels.size() + 1; // 1 cluster
}

CISCServer::~CISCServer()
{
	if(m_acceptor)
	{
		m_acceptor->close();
		m_acceptor = null;
	}
}

CISCServer::ServerList *CISCServer::getServerList()
{
	return &m_serverList;
}

const stringc& CISCServer::getChannelIP(int id)
{
	FOR_EACH(m_serverList.Channels, i)
	{
		if(m_serverList.Channels[i].ID == id)
			return m_serverList.Channels[i].IP;
	}

	return m_settings->ServerIP;
}

bool CISCServer::init(CNetwork *network)
{
	m_acceptor = network->createAcceptor(m_settings->Port);

	if (!m_acceptor)
	{
		CConsole::print(" ISCServer port %u can't be used !\n", m_settings->Port);
		return false;
	}

	m_serverList.MaxChannels = static_cast<uint>(m_settings->MaxChannels);
	m_serverList.ClusterName = m_settings->ServerName;
	m_serverList.ClusterIP = m_settings->ServerIP;

	return true;
}

bool CISCServer::run()
{
	while (m_acceptor->isNew())
	{
		m_unauths.push_back(Unauthorized(m_acceptor->popClient()));
	}

	FOR_EACH (m_unauths, i)
	{
		if (!m_unauths[i].Client->isConnected())
		{
			m_unauths[i].Client->free();
			m_unauths.erase_fast(i);
			continue;
		}
		else if (!m_unauths[i].Client->incoming().empty())
		{
			while (_handlePacket(&m_unauths[i]));

			if (m_unauths[i].Remove)
			{
				m_unauths.erase_fast(i);
				continue;
			}

			m_unauths[i].Client->incoming().clear();
		}
	}

	ServerList::Channel *channel = 0;

	FOR_EACH (m_serverList.Channels, i)
	{
		channel = &m_serverList.Channels[i];

		if (!channel->Client->isConnected())
		{
			CConsole::print(" Lost connection to GameServer \"%s\".\n", channel->Name.c_str());

			channel->Client->free();
			m_serverList.Channels.erase(i);
			continue;
		}
		else if (!channel->Client->incoming().empty())
		{
			//while (_handlePacket(t_cluster));

			channel->Client->incoming().clear();
		}
	}

	return true;
}

bool CISCServer::_handlePacket(Unauthorized* unauth)
{
	CByteArray &packet = unauth->Client->incoming();

	if(packet.getByte() != 0x6b)
		return false;

	uint packetSize = static_cast<uint>(packet.getInt());
	if (packetSize > packet.size() - 5)
		return false;

	int command = packet.getInt();

	switch (command)
	{
	case 0x01:
		_cmdHandler_auth(unauth);
		return false;

	default:
		{
#ifdef _DEBUG
			char buffer[256];
			sprintf(buffer, "Unknown_CoreISC_%x.txt", command);
			packet.saveFormatted(buffer);
#endif
		}
		break;
	};

	return !packet.end();
}

void CISCServer::_cmdHandler_auth(Unauthorized *unauth)
{
	static char password[256];
	static char ip[256];
	static char name[256];

	if(m_serverList.Channels.size() >= m_serverList.MaxChannels)
	{
		unauth->Client->send(CISCPacketCreator::authAnswer(-1, CISCPacketCreator::ANSWER_TOO_MANY_CHANNELS));
		return;
	}

	CByteArray &packet = unauth->Client->incoming();

	if(!packet.getString(password, 256))
		return;

	if (xstricmp(m_settings->Password.c_str(), password) != 0)
	{
		unauth->Client->send(CISCPacketCreator::authAnswer(-1, CISCPacketCreator::ANSWER_WRONG_PASSWORD));
		return;
	}

	if(!packet.getString(ip, 256))
		return;

	if(!packet.getString(name, 256))
		return;

	static int newChannelId = -1;
	
	newChannelId++;
	m_serverList.Channels.push_back(ServerList::Channel(unauth->Client, newChannelId, name, ip, packet.getInt()));

	unauth->Remove = true;
	unauth->Client->send(CISCPacketCreator::authAnswer(newChannelId, CISCPacketCreator::ANSWER_OK));

	CConsole::print(" GameServer \"%s\" connected from %s.\n", name, ip);

	packet.clear();
}